﻿using Castle.DynamicProxy;
using Serilog;
using StackExchange.Profiling;
using System;
using System.Diagnostics;
using System.Text;

namespace CrawlerApp.Services.Interceptors
{
    public class DbContextInterceptor : IInterceptor
    {
        private readonly ILogger logger;
        private MiniProfiler profiler;

        public DbContextInterceptor(ILogger logger)
        {
            this.logger = logger.ForContext<DbContextInterceptor>();
        }

        public void Intercept(IInvocation invocation)
        {
            if (invocation.MethodInvocationTarget.IsPublic)
            {
                try
                {
                    profiler = MiniProfiler.StartNew(invocation.Method.Name);
                    invocation.Proceed();
                    profiler.Stop();

                    var result = GetMiniProfilerResult();
#if DEBUG
                    Trace.Write(result);
#else
                    logger.Information(result);
#endif
                }
                catch (Exception ex)
                {
                    logger.Error(ex, ex.Message);
                }
            }
        }

        private string GetMiniProfilerResult()
        {
            if (profiler == null) return string.Empty;

            var sb = new StringBuilder();

            foreach(var timing in profiler.GetTimingHierarchy())
            {
                if (timing.HasCustomTimings)
                {
                    foreach(var key in timing.CustomTimings.Keys)
                    {
                        foreach(var customTiming in timing.CustomTimings[key])
                        {
                            sb.Append($"{key} - {customTiming.ExecuteType}\t:").AppendLine(customTiming.StackTraceSnippet);
                            sb.AppendLine($"{customTiming.StartMilliseconds}(ms)+{customTiming.DurationMilliseconds}(ms)");
                            sb.AppendLine(customTiming.CommandString);
                            sb.AppendLine();
                        }
                    }
                }
            }
            return sb.ToString();
        }
    }
}